/*
 *      process_list.cpp
 *
 *      Copyright 2009 AzureSky <AzureSky.fedora@gmail.com>
 *
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *      MA 02110-1301, USA.
 */

#include "process_list.h"

process_list::process_list()
{
	m_process_list.clear();

}

process_list::~process_list()
{
	clear_all();
}

void process_list::clear_all()
{
	PROCESS_LIST::iterator proc_it = m_process_list.begin();
	for(;proc_it != m_process_list.end(); proc_it++){
		delete proc_it->second;
		proc_it->second = NULL;
	}
	m_process_list.clear();
}

void process_list::read()
{
	DIR* dir;
	struct dirent* ptr;
	dir = opendir("/proc");
	while((ptr = readdir(dir)) != NULL){
		if(is_pid(ptr->d_name)){
			add_proc(ptr->d_name);
		}
	}
	closedir(dir);

	start();
}

void process_list::start()
{
	m_proc_list_it = m_process_list.begin();
}

bool process_list::is_end()
{
	return (m_proc_list_it == m_process_list.end());
}

bool process_list::next()
{
	if(is_end()){
		return false;
	}

	m_proc_list_it++;
	if(!is_end()){
		return true;
	}

	if(is_end()){
		return false;
	}
}

bool process_list::is_pid(char pid[])
{
	if(pid == NULL){
		return false;
	}

	for(int i = 0;pid[i] != '\0';i++){
		if(!isdigit(pid[i])){
			return false;
		}
	}
	return true;
}

void process_list::add_proc(char* pid)
{
	char file_path[128] = {0};
	sprintf(file_path,"/proc/%s/stat",pid);

	int name_fd = open(file_path,O_RDONLY);
	char proc_buff[256] = {0};
	read(name_fd,proc_buff,sizeof(proc_buff));
	close(name_fd);

	int pid = 0;
	int ppid = 0;
	int pgrp = 0;
	int session = 0;
	int tty_nr = 0;
	int tpgid = 0;
	int exit_signal = 0;
	int processor = 0;

	unsigned int flags = 0;
	unsigned int rt_priority = 0;
	unsigned int policy = 0;

	unsigned long minflt = 0;
	unsigned long cminflt = 0;
	unsigned long majflt = 0;
	unsigned long cmajflt = 0;
	unsigned long utime = 0;
	unsigned long stime = 0;
	unsigned long vsize = 0;
	unsigned long rsslim = 0;
	unsigned long startcode = 0;
	unsigned long endcode = 0;
	unsigned long startstack = 0;
	unsigned long kstkesp = 0;
	unsigned long kstkeip = 0;
	unsigned long signal = 0;
	unsigned long blocked = 0;
	unsigned long sigignore = 0;
	unsigned long sigcatch = 0;
	unsigned long wchan = 0;
	unsigned long nswap = 0;
	unsigned long cnswap = 0;
	unsigned long guest_time = 0;

	long cutime = 0;
	long cstime = 0;
	long priority = 0;
	long nice = 0;
	long num_threads = 0;
	long itrealvalue = 0;
	long rss = 0;
	long cguest_time = 0;

	unsigned long long starttime = 0;
	unsigned long long delayacct_blkio_ticks = 0;

	char comm[20] = {0};
	char state = "";

	int result = sscanf(proc_buff,"%d %s %c %d %d %d %d %d %u %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %llu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu %lu %ld",
							&pid,comm,&state,&ppid,&pgrp,&session,&tty_nr,&tpgid,&flags,&minflt,
							&cminflt,&majflt,&cmajflt,&utime,&stime,&cutime,&cstime,&priority,&nice,&num_threads,
							&itrealvalue,&starttime,&vsize,&rss,&rsslim,&startcode,&endcode,&startstack,&kstkesp,&kstkeip,
							&signal,&blocked,&sigignore,&sigcatch,&wchan,&nswap,&cnswap,&exit_signal,&processor,&rt_priority,
							&policy,&delayacct_blkio_ticks,&guest_time,&cguest_time);

	if(result == -1){
		return -1;
	}

	proc_link_ptr p_proc_link = new proc_link;
	memset(p_proc_link,0,sizeof(p_proc_link));

	p_proc_link->name = comm;
	p_proc_link->nice = nice;

	m_process_list.insert(PROCESS_LIST::value_type(pid,p_proc_link));
}

int process_list::get_pid()
{
	return m_proc_list_it->first;
}

long process_list::get_nice()
{
	proc_link_ptr p_proc_link = m_proc_list_it->second;
	if(p_proc_link == NULL){
		return -99;
	}

	return p_proc_link->nice;
}
